/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package VocSymbTest2;

import java.util.ArrayList;
/**
 *
 * @author StiggieBig
 */
public class Grammar {
	int pos = 0;
	String nonTerminals;
	String terminals;
	String specsymbs;
	ArrayList<String> gramrules;
	VocabularySymbolSet<Terminal> allTerminals;
	VocabularySymbolSet<NonTerminal> allNonTerminals;
	VocabularySymbolSet<SpecialSymbol> allSpecialSymbols;
	VocabularySymbolSet<VocabularySymbol> allVocabularySymbols;
	GrammarRuleSet<GrammarRule> allGrammarRules;
	ItemSetFamily canonicalSetOfItems;
	
	//	default constructor
	Grammar() {    	
		allTerminals = new VocabularySymbolSet<Terminal>();
		allNonTerminals = new VocabularySymbolSet<NonTerminal>();
		allVocabularySymbols = new VocabularySymbolSet<VocabularySymbol>();
		allSpecialSymbols = new VocabularySymbolSet<SpecialSymbol>();
		allGrammarRules = new GrammarRuleSet<GrammarRule>();
		canonicalSetOfItems = new ItemSetFamily();

		nonTerminals = "SETF";
		terminals = "in(+-*/)";
		specsymbs = "e$";

		gramrules = new ArrayList<>();
		gramrules.add("S E");
		gramrules.add("E E+T");
		gramrules.add("E E-T");
		gramrules.add("E T");
		gramrules.add("T T*F");
		gramrules.add("T T/F");
		gramrules.add("T F");
		gramrules.add("F i");
		gramrules.add("F n");
		gramrules.add("F (E)");

		Initialize();

		ProcessFirst();
		ProcessFollow();
		
		canonicalSetOfItems = Canonical();
	}

	VocabularySymbolSet<Terminal> GetTerminals() {
		return allTerminals;
	}

	VocabularySymbolSet<NonTerminal> GetNonTerminals() {
		return allNonTerminals;
	}

	VocabularySymbolSet<VocabularySymbol> GetVocabularySymbols() {
		return allVocabularySymbols;
	}

	VocabularySymbolSet<SpecialSymbol> GetSpecialSymbols() {
		return allSpecialSymbols;
	}

	GrammarRuleSet<GrammarRule> GetGrammarRules() {
		return allGrammarRules;
	}

	private void ProcessFirst() {
		VocabularySymbolSet<VocabularySymbol> checked = new VocabularySymbolSet<VocabularySymbol>();
		checked.clear();
		for(VocabularySymbol tempVocabularySymbol : allVocabularySymbols){
			tempVocabularySymbol.SetFirst(checked, this);
			checked.clear();
		}
	}

	public void PrintAllFirstSets(){

		for(VocabularySymbol tempNonTerminal : this.GetNonTerminals()){
			tempNonTerminal.Print();
			tempNonTerminal.GetFirst().Print();
			System.out.println();
		}
		for(VocabularySymbol tempTerminal : this.GetTerminals()){
			tempTerminal.Print();
			tempTerminal.GetFirst().Print();
			System.out.println();
		}
	}

	private void ProcessFollow() {
		int numRounds = 0;
		int numAdditions = 0;
		do{
			for(NonTerminal nonTerminal : this.allNonTerminals){
				numAdditions = nonTerminal.SetFollow(this);
			}
			numRounds++;
		}while(numAdditions != 0);
		System.out.printf("ProcessFollow finished with number of rounds is %d.\n", numRounds);
	}    

	void PrintFollows(){
		System.out.println("The follow sets are:");
		System.out.printf("%-3s"," ");
		for(VocabularySymbol terminal : this.allTerminals){
			System.out.printf("%-3s",terminal.symbol);
		}
		System.out.println();
		for(NonTerminal nonTerminal : this.allNonTerminals){
			System.out.printf("%-3s",nonTerminal.GetSymbolChar());
			for(Terminal terminal: this.allTerminals){
				if(nonTerminal.GetFollow().isVocSymbElem(terminal)){
					System.out.printf("%-3s",terminal.GetSymbolChar());
				} else {
					System.out.printf("%-3s", " ");
				}
			}
			System.out.println();
		}
	}

	/*void ProcessCanonicalSetOfItems(Grammar newGrammar){
	    ItemSet bootStrap = new ItemSet();

	    canonicalSetOfItems = bootStrap.Canonical(newGrammar);
	}*/

	public void TestTypes(){
		if((allTerminals.GetVocSymbFromChar(')')) instanceof Terminal){
			System.out.println("successfull type detection");
		} else {
			System.out.println("this sucks");
		}
	}

	public boolean CharIsNonTerm(char charToCheck){
		return allNonTerminals.isCharElem(charToCheck);
	}

	public boolean CharIsTerm(char charToCheck){
		return allTerminals.isCharElem(charToCheck);
	}

	public boolean CharIsSpecial(char charToCheck){
		return allSpecialSymbols.isCharElem(charToCheck);
	}

	public ItemSet Closure (ItemSet I){
		VocabularySymbol symbAfterDot;
		GrammarString emptyString = new GrammarString();
		int addedCount = 0;
		ItemSet toAdd = new ItemSet();
		ItemSet closure = new ItemSet();
		
		Item newItem;
		//	Initially, add every item in this.itemSet to this.closure
		closure.addAll(I);
		addedCount++;
		//
		while(addedCount != 0){
			addedCount = 0;
			toAdd.clear();
			for(Item item : closure){
				if(!item.GetStringAfterDot().isEmpty()){
					symbAfterDot = item.GetSymbAfterDot();
					//System.out.println("The stringAfterDotHead considered is");
					//stringAfterDotHead.Print();
					//System.out.println();
					if(symbAfterDot.IsNonTerm()){
						//itemHead = (NonTerminal) symbAfterDot;
						//System.out.println("The itemHead considered is");
						//itemHead.Print();
						//System.out.println();
						//System.out.println("Considering all grammar rules");
						for(GrammarRule grammarRule : this.GetGrammarRules()){
							//System.out.print("considering grammar rule: ");
							//grammarRule.Print();
							//System.out.println();
							if(grammarRule.GetSource().compareTo(symbAfterDot) == 0){
								newItem = new Item((NonTerminal)symbAfterDot, emptyString, grammarRule.GetTarget());
								toAdd.add(newItem);
									//System.out.println("The newitem is");
									//newItem.Print();
									//System.out.println();
							}
						}
					}
				}
			}
			for(Item item : toAdd){
				if(closure.add(item)){
					addedCount++;
				}
			}
			toAdd.clear();
			//System.out.println("The new closure is");
			//closure.Print();
			//System.out.println();
		}
		System.out.println("The returned closure is");
		closure.Print();
		System.out.println();
		return closure;
	}

	public ItemSet Goto(ItemSet I, VocabularySymbol vocabSymb){
		ItemSet addItemSet = new ItemSet();
		Item newItem;
		GrammarString newBeforeDotString;
		GrammarString newAfterDotString;
		VocabularySymbol tempVocSymb;
		//while(addedCount != 0){

		System.out.printf("The VocabularySymbol for Goto is: %c.\n", vocabSymb.GetSymbolChar());
		for(Item item : I){
			System.out.println("The itemSet considered is");
			I.Print();
			System.out.println();

			System.out.println("The item considered is");
			item.Print();
			System.out.println();
			newBeforeDotString = new GrammarString(item.GetStringBeforeDot());
			newAfterDotString = new GrammarString(item.GetStringAfterDot());
			if(!newAfterDotString.isEmpty()){
				System.out.println("The new beforeDotString isa");
				newBeforeDotString.Print();
				System.out.println();
				System.out.println("The new afterDotString isa");
				newAfterDotString.Print();
				System.out.println();

				tempVocSymb = newAfterDotString.GetInitialSymb();
				if(tempVocSymb.compareTo(vocabSymb) == 0){
					System.out.println("The new tempVocSymb is");
					tempVocSymb.Print();
					System.out.println();

					newBeforeDotString.add(tempVocSymb);

					System.out.println("The new beforeDotString isb");
					newBeforeDotString.Print();
					System.out.println();

					newAfterDotString.remove(0);
					newItem = new Item(item.GetSource(), newBeforeDotString, newAfterDotString);
					addItemSet.add(newItem);
					System.out.println("The new afterDotString isb");
					newAfterDotString.Print();
					System.out.println();

					newItem.Print();  
					System.out.println("The additemset now isb");
					addItemSet.Print();
					System.out.println();
				}
			}
			System.out.println("The new beforeDotString isc");
			newBeforeDotString.Print();
			System.out.println();

			System.out.println("The new afterDotString isc");
			newAfterDotString.Print();
			System.out.println();
		}
		System.out.println("The itemset returned is by Goto is:");
		addItemSet.Print();
		System.out.println();
		return Closure(addItemSet);
	}
	
	ItemSetFamily Canonical(){
        int addCount = 0;
        Item startItem;
        ItemSet startItemSet = new ItemSet();
        ItemSetFamily canonical = new ItemSetFamily();
        ItemSetFamily toAdd = new ItemSetFamily();
        
        ItemSet gotoSet = new ItemSet();
        
        GrammarString emptyString = new GrammarString();
        GrammarString newStringAfterDot = new GrammarString(allNonTerminals.GetVocSymbFromChar('E'));
        
        startItem = new Item(allNonTerminals.GetVocSymbFromChar('S'), emptyString, newStringAfterDot);
        
        startItemSet.add(startItem);
        canonical.add(Closure(startItemSet));
        System.out.println("The beginning canonical set is: ");
        canonical.PrintSet();
        System.out.println();
        do{
            addCount = 0;
            //System.out.println("For each item set in canonical: ");
            for (ItemSet itemSet : canonical) {
                for (VocabularySymbol vocSymb: allVocabularySymbols) {
                    gotoSet = Goto(itemSet,vocSymb);
                    if(!gotoSet.isEmpty()){
                    		toAdd.add(gotoSet);
                    }
                }
            }
            for(ItemSet itemSet : toAdd){
				if(canonical.add(itemSet)){
					addCount++;
				}
			}
            System.out.printf("ADDCOUNT IS: %d.\n", addCount);
			toAdd.clear();
        }while(addCount != 0);
        //canonical.PrintItemSetFamily();
        //System.out.println();
        return canonical;
    }

	public void PrintCanonicalSets(){
        System.out.println("The canonical sets are: ");
        canonicalSetOfItems.PrintList();
    }
	/*public Boolean GotoReduce(VocabularySymbol X,ItemSet B, Grammar grammar){
    boolean leftReduces = true;
    ItemSet tempItemSet = new ItemSet();
    //System.out.println("The itemSet to check goto reduction by " + X.GetSymbolChar() + " is:");
    //this.Print();
    //System.out.println();
    //System.out.println("The set to be reduced to is:");
    //B.Print();
    //System.out.println();

    tempItemSet = new ItemSet(Goto(this,X,grammar));
    //System.out.println("The reduction is:");
    //tempItemSet.Print();
    //System.out.println();
    if(!tempItemSet.itemSet.isEmpty()){
        for(Item item : tempItemSet.itemSet){
            if(!B.itemSet.contains(item)){
                leftReduces = false;
            }
        }
    }else if(tempItemSet.itemSet.isEmpty()){
        leftReduces = false;
    }

    return leftReduces;
}*/

	/*public Boolean GotoEquals(VocabularySymbol X,ItemSet B, Grammar grammar){
    boolean leftReduces = true;
    boolean rightReduces = true;
    ItemSet tempItemSet = new ItemSet();
    tempItemSet = new ItemSet(Goto(this,X,grammar));
    for(Item item : tempItemSet.itemSet){
        if(!B.itemSet.contains(item)){
            leftReduces = false;
        }
    }
    tempItemSet = new ItemSet(Goto(B,X,grammar));
    for(Item item : tempItemSet.itemSet){
        if(!B.itemSet.contains(item)){
            rightReduces = false;
        }
    }

    return leftReduces && rightReduces;
}*/

	/*ItemSetFamily Canonical(Grammar grammar){
    int addCount = 1;
    Boolean doAdd = true;
    Item startItem = new Item();
    ItemSet startItemSet = new ItemSet();
    ItemSetFamily canonical = new ItemSetFamily();
    ItemSetFamily addToCanonical = new ItemSetFamily();

    ItemSet gotoSet = new ItemSet();

    GrammarString emptyString = new GrammarString();
    GrammarString newStringAfterDot = new GrammarString(new NonTerminal('E'));

    startItem = new Item(new NonTerminal('S'), emptyString, newStringAfterDot);

    startItemSet.itemSet.add(startItem);

    canonical.itemSetFamily.add(Closure(startItemSet, grammar));
    canonical.canonicalSets.add(Closure(startItemSet, grammar));
    addToCanonical = new ItemSetFamily(canonical);
    //System.out.println("The beginning canonical set is: ");
    //addToCanonical.Print();
    //System.out.println();
    while(addCount != 0){
        addCount = 0;
        //System.out.println("For each item set in canonical: ");
        for (ItemSet addItemSet : canonical.canonicalSets) {
            Iterator<VocabularySymbol> it = grammar.allNonTerminals.vocabularySymbolSet.iterator();
            it.next();
            for (; it.hasNext();) {
                VocabularySymbol vocSymb = it.next();
                gotoSet = new ItemSet(Goto(addItemSet,vocSymb,grammar));
                if(!gotoSet.itemSet.isEmpty()){//&& !canonical.itemSetFamily.contains(gotoSet)
                    //if(vocSymb.symbol == 'E'){
                    //    addItemSet.Print();
                    //    System.out.println();
                    //    gotoSet.Print();
                    //    System.out.println( "");
                    //}
                    if(addToCanonical.itemSetFamily.add(gotoSet)){
                        addToCanonical.canonicalSets.add(gotoSet);
                        //System.out.println("add to canonical set it: ");
                        //addToCanonical.Print();
                        //System.out.println("terminals");
                        //System.out.println();
                    }
                }
            }
            for(VocabularySymbol vocSymb : grammar.allTerminals.vocabularySymbolSet){
                //System.out.print("The vocabulary symbol considered is: ");
                //vocSymb.Print();
                //if(vocSymb.GetSymbolChar() == '(')
                //   vocSymb.Print();   
                gotoSet = new ItemSet(Goto(addItemSet,vocSymb,grammar));
                //System.out.println("my new gotoset is");
                //gotoSet.Print();
                if(!gotoSet.itemSet.isEmpty()){//&& !canonical.itemSetFamily.contains(gotoSet)){

                    if(addToCanonical.itemSetFamily.add(gotoSet)){
                        addToCanonical.canonicalSets.add(gotoSet);
                        //System.out.println("add to canonical set it: ");
                        //addToCanonical.Print();
                        //System.out.println("nonterminals");
                        //System.out.println();
                    }
                }
            }
        }
        for (Iterator<ItemSet> it = addToCanonical.canonicalSets.iterator(); it.hasNext();) {
            ItemSet itemSet = it.next();
            if(canonical.itemSetFamily.add(new ItemSet(itemSet))){
                canonical.canonicalSets.add(new ItemSet(itemSet));
                addCount++;
            }
        }
        addToCanonical = new ItemSetFamily();
    }
    //canonical.PrintItemSetFamily();
    //System.out.println();
    canonical.ConstructCanonicalSetSetsGotoReduced(grammar);
    canonical.PrintCanonicalSets();

    canonical.PrintCanonicalSetsNonKernal(canonical.ConstructCanonicalSetsNonKernal(canonical));

    canonical.PrintCanonicalSetsGotoReduced();
    canonical.PrintTransitionTable();
    canonical.PrintGotoTable(grammar);
    canonical.PrintActionTable(grammar);
    return canonical;
}*/

	//	Test grammarstring production
	public void TestGrammarString(){
		VocabularySymbol tempVocSymb;
		GrammarString tempGramString;
		tempGramString = new GrammarString();
		tempVocSymb = TestType('E');
		tempGramString.add(tempVocSymb);
		tempVocSymb = TestType('+');
		tempGramString.add(tempVocSymb);
		tempVocSymb = TestType('T');
		tempGramString.add(tempVocSymb);
		tempGramString.PrintDebug();

		//Test GrammarStringcopy
		GrammarString newGrammarString;
		newGrammarString = tempGramString;
		newGrammarString.PrintDebug();
	}

	public VocabularySymbol TestType(char c){
		VocabularySymbol vocSymb;
		if(CharIsTerm(c)){
			vocSymb = (Terminal) allTerminals.GetVocSymbFromChar(c);
			//System.out.println(c + " is of type " + vocSymb.getClass());
		} else if(CharIsNonTerm(c)){
			vocSymb = (NonTerminal) allNonTerminals.GetVocSymbFromChar(c);
			//System.out.println(c + " is of type " + vocSymb.getClass());
		} else if(CharIsSpecial(c)){
			vocSymb = (SpecialSymbol) allSpecialSymbols.GetVocSymbFromChar(c);
			//System.out.println(c + " is of type " + vocSymb.getClass());
		} else {
			vocSymb = null;
		}

		return vocSymb;
	}

	public void Initialize(){
		this.InitializeVocSymbs();
		this.InitializeGrammarRules();
	}

	public void InitializeVocSymbs(){
		int count = 0;
		for(char c : nonTerminals.toCharArray()){
			NonTerminal toAdd = new NonTerminal(c, count);
			allNonTerminals.add(toAdd);
			allVocabularySymbols.add(toAdd);
			count++;
		}
		for(char c : terminals.toCharArray()){
			Terminal toAdd = new Terminal(c, count);
			allTerminals.add(toAdd);
			allVocabularySymbols.add(toAdd);
			count++;
		}
		for(char c : specsymbs.toCharArray()){
			SpecialSymbol toAdd = new SpecialSymbol(c, count);
			allTerminals.add(toAdd);
			allSpecialSymbols.add(toAdd);
			allVocabularySymbols.add(toAdd);
			count++;
		}
	}

	public void InitializeGrammarRules(){
		char source;
		String target;
		for(String s : gramrules){
			source = s.charAt(0);
			target = s.substring(2);
			allGrammarRules.add(InitializeGrammarRule(source, target));
		}
		//allGrammarRules.Print();
	}

	public GrammarRule InitializeGrammarRule(char source, String target){
		VocabularySymbol tempVocSymb;
		GrammarString tempGramString;
		tempGramString = new GrammarString();
		GrammarRule tempGramRule;

		for(char c : target.toCharArray()){
			tempVocSymb = TestType(c);
			tempGramString.add(tempVocSymb);
		}
		tempVocSymb = TestType(source);

		tempGramRule = new <VocabularySymbol>GrammarRule((NonTerminal)tempVocSymb, tempGramString);
		//tempGramRule.PrintDebug();
		return tempGramRule;
	}
}
